/***************************************************************************
 *   Copyright (C) 2008 by						   *
 *          Ali Abdou							   *
 *          Camille Gallet						   *
 *          Rémy Hubscher						   *
 *          Regis Strub							   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "GameEngine.hpp"
#include "Player.hpp"
#include "PlayerIA.hpp"

GameEngine::box GameEngine::board[9]={SQUARE_ONLY,	SQUARE_ONLY,	SQUARE_ONLY,
				      SQUARE_ONLY,	EMPTY,		SQUARE_ONLY,
				      SQUARE_ONLY,	SQUARE_ONLY,	SQUARE_ONLY};

GameEngine * GameEngine::instance=NULL;
QVector<Plateau> GameEngine::coups;
unsigned int GameEngine::currentPos=0;;

GameEngine::GameEngine() : QObject(NULL)
{
    // Joueur 1
    p1 = NULL;
    p2 = NULL;
    readConf();

    // Remplissage du nouveau Plateau
}

GameEngine * GameEngine::getInstance()
{
	if(!instance)
	    instance = new GameEngine();
	return instance;
}

void GameEngine::newGame()
{
    coups.clear();
    currentPos=0;
    GameEngine::box  b[9]={SQUARE_ONLY,	SQUARE_ONLY,	SQUARE_ONLY,
				      SQUARE_ONLY,	EMPTY,		SQUARE_ONLY,
				      SQUARE_ONLY,	SQUARE_ONLY,	SQUARE_ONLY};
    for(int i=0;i<9;i++)
        board[i]=b[i];
    currentPlayer=p2;
    Board::getInstance()->setBoard(board);
}



void GameEngine::connecting(PrologEngine* pl, GameFrame* gf)
{
    // Le joueur demande un coup à l'IA
    connect((QObject*)p1,SIGNAL(askingMoveIA(GameEngine::box*,GameEngine::player)),(QObject*)pl,SLOT(recupAskingMove(GameEngine::box*,GameEngine::player)));
    connect((QObject*)p2,SIGNAL(askingMoveIA(GameEngine::box*,GameEngine::player)),(QObject*)pl,SLOT(recupAskingMove(GameEngine::box*,GameEngine::player)));

    connect((QObject*)p1,SIGNAL(askingVict(bool&,GameEngine::box*,GameEngine::player)),(QObject*)pl,SLOT(victoire(bool&,GameEngine::box*,GameEngine::player)));
    connect((QObject*)p2,SIGNAL(askingVict(bool&,GameEngine::box*,GameEngine::player)),(QObject*)pl,SLOT(victoire(bool&,GameEngine::box*,GameEngine::player)));

    // Le joueur demande un coup à la GameFrame
    connect((QObject*)p1,SIGNAL(askingMove(GameEngine::player)),(QObject*)gf,SLOT(recupAskingMove(GameEngine::player)));

    connect((QObject*)Board::getInstance(),SIGNAL(sendMoving(Moving&)),(QObject*)this,SLOT(recupMouseMove(Moving&)));

    connect((QObject*) this,SIGNAL(jouerCoup(GameEngine::box*, Moving&,GameEngine::player)),(QObject*)pl,SLOT(humanPlay(GameEngine::box*, Moving&,GameEngine::player)));
    
    connect((QObject*)this,SIGNAL(gameOver(bool)),(QObject*)Board::getInstance(),SLOT(setConnect(bool)));
    
    connect((QObject*)Board::getInstance(),SIGNAL(valideCoup(bool&,Moving&, GameEngine::box*)),(QObject*)this,SLOT(forwardCoup(bool& ,Moving&, GameEngine::box*)));
    
    connect((QObject*)this,SIGNAL(coupForward(bool& ,Moving&, GameEngine::box* , GameEngine::player )),(QObject*)pl,SLOT(coupValide(bool& ,Moving& , GameEngine::box* , GameEngine::player )));
}



void GameEngine::recupMouseMove(Moving &m)
{

     //currentPlayer->joue(board);
        if(currentPlayer==p1)
              currentPlayer=p2;
        else if(currentPlayer==p2)
              currentPlayer=p1;
     coups.insert(currentPos,Plateau(board));;


     currentPos++;
     emit jouerCoup(board, m,currentPlayer->getId());
     Board::getInstance()->setBoard(board);
     bool vict=currentPlayer->victoire(board);
     if(vict==false){

     	jouer();
    	}
     else{
     	QMessageBox::information(NULL,"Game Over",currentPlayer->getName()+ " wins!");
    	emit gameOver(false);
    }
    	
}

bool GameEngine::jouer(){
    bool vict=false;
    while(!vict && !((currentPlayer==p1 && p2->human()) || (currentPlayer==p2 && p1->human()))){
        if(currentPlayer==p1)
              currentPlayer=p2;
        else if(currentPlayer==p2)
              currentPlayer=p1;
        currentPlayer->joue(board);
        vict=currentPlayer->victoire(board);
        Board::getInstance()->setBoard(board);
    }
    if(vict==true)
    	QMessageBox::information(NULL,"Game Over",currentPlayer->getName()+ " wins!");
    return vict;
}

void GameEngine::forwardCoup(bool& ok,Moving &m, GameEngine::box* plateau){
        if(currentPlayer==p1)
			emit coupForward( ok, m, plateau, p2->getId());
        else if(currentPlayer==p2)
			emit coupForward( ok, m, plateau, p1->getId());

}

void GameEngine::revertCoup(){
//	QMessageBox::information(NULL,"",QString("%1 %2").arg(currentPos).arg(coups.size()));
       if (currentPos>0){
            Board::getInstance()->setBoard(coups[currentPos-1].getPlateau());
            currentPos--;
       }else
	QMessageBox::information(NULL,"","retour impossible");

}

void GameEngine::nextCoup(){
       if (currentPos<coups.size()){
            Board::getInstance()->setBoard(coups[currentPos+1].getPlateau());
            currentPos++;
       }else
	QMessageBox::information(NULL,"","coup suivant impossible");
}

void GameEngine::changeConf(QString p1Name, QString p2Name, bool p1Human, bool p2Human){
    
    QSettings settings("UTBM","force3");
    settings.setValue("p1Name",p1Name);
    settings.setValue("p2Name",p2Name);
    settings.setValue("p1Human",p1Human);
    settings.setValue("p2Human",p2Human);
    if(p1!=NULL) delete p1;
    if(p2!=NULL) delete p2;
    if(p1Human){
       p1=new Player(BLUE,p1Name);
    }else{
       p1=new PlayerIA(BLUE,p1Name);
    }
    if(p2Human){
       p2=new Player(RED,p2Name);
    }else{
       p2=new PlayerIA(RED,p2Name);
    }
    currentPlayer = p2;
}

void GameEngine::readConf(){
    QString p1Name,p2Name;
    bool p1Human, p2Human;
    QSettings settings("UTBM","force3");
    p1Name=settings.value("p1Name", "Bob's Crosses").toString();
    p2Name=settings.value("p2Name","Alice's Noughts").toString();
    p1Human=settings.value("p1Human",false).toBool();
    p2Human=settings.value("p2Human",true).toBool();
    if(p1!=NULL) delete p1;
    if(p2!=NULL) delete p2;
    if(p1Human){
       p1=new Player(BLUE,p1Name);
    }else{
       p1=new PlayerIA(BLUE,p1Name);
    }

    if(p2Human){
       p2=new Player(RED,p2Name);
    }else{
       p2=new PlayerIA(RED,p2Name);
    }

    currentPlayer = p2;
    newGame();
}




/*****************************************************************************************/
Plateau::Plateau(GameEngine::box *pl){
     for(int i=0;i<9;i++)
        p[i]=pl[i];
}

GameEngine::box Plateau::operator[](int i) const{
     return p[i];
}

GameEngine::box* Plateau::getPlateau(){
     return p;
}
